﻿using Mapster;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using MongoDB.Driver;
using Shipeng.Util;
using SqlSugar;
using System.Linq.Expressions;
using YNTK.Common.Const;
using YNTK.Common.Enum;
using YNTK.Common.Extension;
using YNTK.Common.Filter;
using YNTK.Data.MongoDB.Repositorie;
using YNTK.Dependency;
using YNTK.DynamicApiController;
using YNTK.FriendlyException;
using YNTK.General.Entitys.Dto.Notice;
using YNTK.General.Entitys.Notice;
using YNTK.General.Interface;
using YNTK.LinqBuilder;
using YNTK.SimpleWorkflow.Interface;
using YNTK.System.Entitys.Permission;
using YNTK.System.Interfaces.Common;
using YNTK.System.Interfaces.Permission;

namespace YNTK.General
{
    /// <summary>
    /// (会议)培训通知服务的实现
    /// 版 本：V1.0.0.0
    /// 版 权：云南通科科技有限公司（https://www.yntkkj.com）
    /// 作 者：李仕鹏
    /// 日 期：2022.11.08
    /// </summary>
    [ApiDescriptionSettings(Tag = "(会议)培训通知", Name = "TrainingNotice", Order = 770)]
    [Route("api/[controller]")]
    public class TrainingNoticeService : ITrainingNoticeService, IDynamicApiController, ITransient
    {
        private readonly ISqlSugarRepository<TrainingNoticeEntity> _repository;//(会议)培训通知仓储
        private readonly IMongoDBRepository<TrainingNoticeEntity> _mongoDbRepository;//(会议)培训通知mongodb仓储
        private readonly ISqlSugarRepository<TrainingNoticeFlowConfigEntity> _configRepository;//(会议)培训通知关联流程节点仓储
        private readonly IMongoDBRepository<TrainingNoticeFlowConfigEntity> _configMongoDbRepository;//(会议)培训通知关联流程节点mongodb仓储
        private readonly ISqlSugarRepository<TrainingNoticeFileEntity> _filesRepository;//(会议)培训通知相关附件仓储
        private readonly IMongoDBRepository<TrainingNoticeFileEntity> _filesMongoDbRepository;//(会议)培训通知相关附件mongodb仓储
        private readonly ISqlSugarRepository<TrainingNoticeAuditRecordsEntity> _auditRepository;//(会议)培训通知审核记录仓储
        private readonly IMongoDBRepository<TrainingNoticeAuditRecordsEntity> _auditMongoDbRepository;//(会议)培训通知审核记录mongodb仓储
        private readonly ISqlSugarRepository<TrainingNoticeAuditRecordFilesEntity> _auditFileRepository;//(会议)培训通知审核记录相关附件仓储
        private readonly IMongoDBRepository<TrainingNoticeAuditRecordFilesEntity> _auditFileMongoDbRepository;//(会议)培训通知审核记录相关附件mongodb仓储

        private readonly ITkUsersService _tkUsersService;//用户服务
        private readonly IOrganizeService _organizeService;//组织服务
        private readonly IMechanismService _mechanismService;//机构服务
        private readonly IFileService _fileService;//文件服务
        private readonly ITkRoleService _tkRoleService;//角色服务
        private readonly ISimpleWorkflowService _simpleWorkflowService;//工作流服务
        private readonly HttpContext _httpContext;

        private readonly string _notices = "general_training_notices";//mongodb中(会议)培训通知数据集名称
        private readonly string _flowconfigs = "general_training_notice_flowconfigs";//mongodb中(会议)培训通知关联流程节点数据集名称
        private readonly string _files = "general_training_notice_files";//mongodb中(会议)培训通知相关附件数据集名称
        private readonly string _audits = "general_training_notice_auditrecords";//mongodb中(会议)培训通知审核记录数据集名称
        private readonly string _auditFiles = "general_training_notice_auditrecord_files";//mongodb中(会议)培训通知审核记录相关附件数据集名称

        /// <summary>
        /// 构造方法依赖注入
        /// </summary>
        /// <param name="repository">(会议)培训通知仓储</param>
        /// <param name="mongoDbRepository">(会议)培训通知mongodb仓储</param>
        /// <param name="configRepository">(会议)培训通知关联流程节点仓储</param>
        /// <param name="configMongoDbRepository">(会议)培训通知关联流程节点mongodb仓储</param>
        /// <param name="filesRepository">(会议)培训通知相关附件仓储</param>
        /// <param name="filesMongoDbRepository">(会议)培训通知相关附件mongodb仓储</param>
        /// <param name="auditRepository">(会议)培训通知审核记录仓储</param>
        /// <param name="auditMongoDbRepository">(会议)培训通知审核记录mongodb仓储</param>
        /// <param name="auditFileRepository">(会议)培训通知审核记录相关附件仓储</param>
        /// <param name="auditFileMongoDbRepository">(会议)培训通知审核记录相关附件mongodb仓储</param>
        /// <param name="tkUsersService">用户服务</param>
        /// <param name="organizeService">组织服务</param>
        /// <param name="mechanismService">机构服务</param>
        /// <param name="fileService">文件服务</param>
        /// <param name="tkRoleService">角色服务</param>
        /// <param name="simpleWorkflowService">工作流服务</param>
        public TrainingNoticeService(ISqlSugarRepository<TrainingNoticeEntity> repository,
            IMongoDBRepository<TrainingNoticeEntity> mongoDbRepository,
            ISqlSugarRepository<TrainingNoticeFlowConfigEntity> configRepository,
            IMongoDBRepository<TrainingNoticeFlowConfigEntity> configMongoDbRepository,
            ISqlSugarRepository<TrainingNoticeFileEntity> filesRepository,
            IMongoDBRepository<TrainingNoticeFileEntity> filesMongoDbRepository,
            ISqlSugarRepository<TrainingNoticeAuditRecordsEntity> auditRepository,
            IMongoDBRepository<TrainingNoticeAuditRecordsEntity> auditMongoDbRepository,
            ISqlSugarRepository<TrainingNoticeAuditRecordFilesEntity> auditFileRepository,
            IMongoDBRepository<TrainingNoticeAuditRecordFilesEntity> auditFileMongoDbRepository,
            ITkUsersService tkUsersService, IOrganizeService organizeService,
            IMechanismService mechanismService, IFileService fileService,
            ITkRoleService tkRoleService, ISimpleWorkflowService simpleWorkflowService)
        {
            _repository = repository;
            _mongoDbRepository = mongoDbRepository;
            _configRepository = configRepository;
            _configMongoDbRepository = configMongoDbRepository;
            _filesRepository = filesRepository;
            _filesMongoDbRepository = filesMongoDbRepository;
            _auditRepository = auditRepository;
            _auditMongoDbRepository = auditMongoDbRepository;
            _auditFileRepository = auditFileRepository;
            _auditFileMongoDbRepository = auditFileMongoDbRepository;

            _tkUsersService = tkUsersService;
            _organizeService = organizeService;
            _mechanismService = mechanismService;
            _fileService = fileService;
            _tkRoleService = tkRoleService;
            _simpleWorkflowService = simpleWorkflowService;
            _httpContext = App.HttpContext;
        }


        /// <summary>
        /// 分页获取(会议)培训通知数据数据
        /// </summary>
        /// <param name="query">查询(会议)培训通知数据请求模型</param>
        /// <returns></returns>
        [HttpPost("gets")]
        public async Task<TkPageResult<TrainingNoticeListDto>> Gets([FromBody] QueryTrainingNoticeFilterReqyestModel query)
        {
            try
            {
                var user = _httpContext.User.FindFirst(ClaimConst.CLAINM_USERID);
                string userId = user.Value;
                string organizeId = user.Subject.FindFirst(ClaimConst.ORGANIZEID).Value;
                string mechanismId = user.Subject.FindFirst(ClaimConst.MECHANISMID).Value;
                string roleId = user.Subject.FindFirst(ClaimConst.ROLEID).Value;
                //账号类型【0.平台运营人员 1.超级管理员 2.组织管理员 3.组织用户 4.第三方登录用户 5.游客用户】
                var authenticationType = user.Subject.FindFirst(ClaimConst.ACCOUNTTYPE).Value;

                var pageList = new SqlSugarPagedList<TrainingNoticeListDto>();

                #region 组装查询条件
                Expression<Func<TrainingNoticeEntity, bool>> where = m =>
                 m.DeleteMark == null && (m.CreatorUserId == userId ||
               (m.ConfereeUserIds.Contains(userId) && m.EnabledMark==1) ||
               (m.SharedScope == 0 && m.OrganizeId == organizeId && m.EnabledMark == 1) ||
               (m.SharedScope == 1 && m.MechanismId == mechanismId && m.EnabledMark == 1) ||
               (m.SharedScope == 2 && m.SharedScopeValue.Contains(roleId) && m.EnabledMark == 1) ||
               (m.SharedScope == 3 && m.SharedScopeValue.Contains(userId) && m.EnabledMark == 1) ||
               m.DisposeUserIds.Contains(userId) || m.NextDisposenUserId == userId);

                if (query.enabledMark == 1) where = where.And(m => m.EnabledMark == 1);
                if (query.enabledMark == 0) where = where.And(m => m.EnabledMark != 1);
                if (!string.IsNullOrWhiteSpace(query.mechanismId))
                {
                    string queryMechanismId = await _mechanismService.GetIdAsync(query.mechanismId, organizeId);
                    where = where.And(m => m.MechanismId == queryMechanismId);
                }
                if (query.sharedScope != null)
                    where = where.And(m => m.SharedScope == query.sharedScope.GetHashCode());
                if (query.state != null) where = where.And(m => m.State == query.state.GetHashCode());
                if (query.startDate != null)
                {
                    var start = Ext.GetDateTime(query.startDate.ToString());
                    start = new DateTime(start.Year, start.Month, start.Day, 00, 00, 00, 000);
                    where = where.And(m=>m.TrainingDate>= start);
                }
                if (query.endDate != null)
                {
                    var end = Ext.GetDateTime(query.endDate.ToString());
                    end = new DateTime(end.Year, end.Month, end.Day, 23, 59, 59, 999);
                    where = where.And(m => m.TrainingDate <= end);
                }
                if (!string.IsNullOrWhiteSpace(query.keyword))
                    where = where.And(m => m.Title.Contains(query.keyword) || m.TrainingSite.Contains(query.keyword) ||
                    m.TrainingMethod.Contains(query.keyword) || m.Title.Contains(query.keyword));
                #endregion

                #region 从mongodb中获取(会议)培训通知数据
                //排序生成器
                var builderSort = Builders<TrainingNoticeEntity>.Sort;
                //排序约束   Ascending 正序    Descending 倒序
                var sort = builderSort.Ascending(r => r.SortCode).Descending(r => r.CreatorTime);
                //Item1.结果集 Item2.总条数 Item3.总页数
                (List<TrainingNoticeEntity>, int, int) result =
                    await _mongoDbRepository.GetListAsync(_notices,
                    where, query.currentPage, query.pageSize, null, sort);
                pageList.list = result.Item1.Adapt<List<TrainingNoticeListDto>>();
                pageList.pagination = new PagedModel()
                {
                    PageIndex = query.currentPage,
                    PageSize = query.pageSize,
                    Total = result.Item2,
                    PageCount = result.Item3
                };
                #endregion

                if (!pageList.list.Any())
                {
                    #region 从sqlserver数据库中获取(会议)培训通知数据
                    var sqlResult = await _repository.Entities.Where(where)
                         .OrderBy(r => r.SortCode, OrderByType.Asc)
                         .OrderBy(r => r.CreatorTime, OrderByType.Desc)
                         .ToPagedListAsync(query.currentPage, query.pageSize);
                    pageList.list = sqlResult.list.Adapt<List<TrainingNoticeListDto>>();
                    pageList.pagination = sqlResult.pagination;
                    #endregion
                }
                #region 处理(会议)培训通知返回数据
                if (pageList.list.Any())
                {
                    var orgIds = pageList.list.Select(r => r.organizeId).Distinct().ToList();
                    var orgs = await _organizeService.GetOrganizeListByIds(orgIds);
                    var mechanismIds = pageList.list.Where(r => !string.IsNullOrWhiteSpace(r.mechanismId))
                        ?.Select(r => r.mechanismId.Split(',').ToList())
                        ?.SelectMany(r => r).Distinct().ToList();
                    var mechanisms = !mechanismIds.Any() ? new List<MechanismEntity>() :
                        await _mechanismService.GetMechanismListAsync(null, mechanismIds);
                    var userIds = pageList.list.Select(r => r.creatorUserId).Distinct().ToList().Union(
                        pageList.list.Where(r => !string.IsNullOrWhiteSpace(r.nextDisposenUserId))
                        ?.Select(r => r.nextDisposenUserId)?.Distinct()?.ToList()).ToList();
                    var users = await _tkUsersService.GetUserListByIds(userIds);
                    var nodeIds = pageList.list.Where(r => !string.IsNullOrWhiteSpace(r.nextDisposenNodeId))
                         ?.Select(r => r.nextDisposenNodeId)?.Distinct()?.ToList();
                    var nodes = !nodeIds.Any() ? new List<TrainingNoticeFlowConfigEntity>() :
                        await GetFlowConfigListAsync(r => nodeIds.Contains(r.Id));
                    pageList.list.ForEach(notice =>
                    {
                        notice.sharedScopeText = EnumHelper.GetEnumDescriptionString
                        (notice.sharedScope, typeof(SharedScopeEnum));
                        notice.stateText = EnumHelper.GetEnumDescriptionString
                        (notice.state, typeof(AuditStateEnum));
                        if (!string.IsNullOrWhiteSpace(notice.organizeId))
                            notice.organizeName = orgs?.FirstOrDefault(r => r.Id == notice.organizeId)?.FullName;
                        if (!string.IsNullOrWhiteSpace(notice.mechanismId))
                        {
                            notice.mechanismName = string.Join('/', mechanisms
                                ?.Where(r => notice.mechanismId.Split(',').ToList().Contains(r.Id))
                                ?.Select(r => r.Name)?.ToList());
                        }
                        if (!string.IsNullOrWhiteSpace(notice.creatorUserId))
                            notice.creatorUserName = users?.FirstOrDefault(r => r.Id == notice.creatorUserId)?.RealName;
                        if (!string.IsNullOrWhiteSpace(notice.nextDisposenUserId))
                            notice.nextDisposenUserName = users?.FirstOrDefault(r => r.Id == notice.nextDisposenUserId)?.RealName;
                        if (!string.IsNullOrWhiteSpace(notice.nextDisposenNodeId))
                            notice.nextDisposenNodeName = nodes?.FirstOrDefault(r => r.Id == notice.nextDisposenNodeId)?.NodeName;
                    });
                }
                #endregion

                return TkPageResult<TrainingNoticeListDto>.Success(pageList);
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains("[")) throw YNTKException.Oh($"{ex.Message}");
                throw YNTKException.Oh($"分页获取(会议)培训通知数据数据发生异常：{ex.Message}");
            }
        }


        #region 流程节点
        /// <summary>
        /// 获取(会议)培训通知流程节点配置数据
        /// </summary>
        /// <param name="where">条件</param>
        /// <returns></returns>
        private async Task<List<TrainingNoticeFlowConfigEntity>> GetFlowConfigListAsync(
            Expression<Func<TrainingNoticeFlowConfigEntity, bool>> where)
        {
            //从mongodb中获取
            var result = await _configMongoDbRepository.GetListAsync(_flowconfigs, where);
            if (result == null || result.Count <= 0)
            {
                //再从sqlserver数据库中获取
                result = await _configRepository.Entities.Where(where).ToListAsync();
            }
            return result;
        }
        #endregion

    }
}
